"""
摄像头管理器
负责摄像头的初始化、帧获取和管理
"""
import cv2
import numpy as np
import logging
import threading
import time
from typing import Optional, Tuple, Callable

logger = logging.getLogger(__name__)


class CameraManager:
    """
    摄像头管理器
    负责摄像头设备的管理、帧获取和基本处理
    """
    
    def __init__(self, 
                 device_path: str = "0", 
                 width: int = 640, 
                 height: int = 480, 
                 fps: int = 30):
        """
        初始化摄像头管理器
        
        Args:
            device_path: 摄像头设备路径（可以是设备ID或路径）
            width: 摄像头分辨率宽度
            height: 摄像头分辨率高度
            fps: 帧率
        """
        # 尝试将device_path转换为整数ID，如果失败则作为字符串路径使用
        try:
            self.device_id = int(device_path)
            self.device_path = device_path
        except ValueError:
            self.device_id = device_path  # 作为路径使用
            self.device_path = device_path
        self.width = width
        self.height = height
        self.fps = fps
        
        # 摄像头对象
        self.cap = None
        self.is_opened = False
        
        # 线程控制
        self._capture_thread = None
        self._capture_running = False
        self._frame_lock = threading.Lock()
        self._current_frame = None
        self._frame_timestamp = 0
        
        # 统计信息
        self.stats = {
            'total_frames': 0,
            'fps_actual': 0.0,
            'last_frame_time': 0.0
        }
        
        # 初始化摄像头
        self._init_camera()
    
    def _init_camera(self):
        """初始化摄像头"""
        try:
            logger.info(f"正在初始化摄像头设备: {self.device_path}")
            
            # 尝试打开摄像头
            self.cap = cv2.VideoCapture(self.device_id)
            
            if not self.cap.isOpened():
                raise RuntimeError(f"无法打开摄像头设备: {self.device_id}")
            
            # 设置摄像头参数
            self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, self.width)
            self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, self.height)
            self.cap.set(cv2.CAP_PROP_FPS, self.fps)
            
            # 获取实际参数
            actual_width = int(self.cap.get(cv2.CAP_PROP_FRAME_WIDTH))
            actual_height = int(self.cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
            actual_fps = self.cap.get(cv2.CAP_PROP_FPS)
            
            self.width, self.height = actual_width, actual_height
            self.is_opened = True
            
            logger.info(f"✅ 摄像头初始化成功")
            logger.info(f"分辨率: {actual_width}x{actual_height}, FPS: {actual_fps}")
            
            # 测试读取一帧
            ret, test_frame = self.cap.read()
            if not ret:
                logger.warning("摄像头测试读取失败")
            else:
                logger.info("摄像头测试读取成功")
                
        except Exception as e:
            logger.error(f"摄像头初始化失败: {e}")
            self.is_opened = False
            if self.cap:
                self.cap.release()
                self.cap = None
            raise
    
    def read_frame(self) -> Tuple[bool, Optional[np.ndarray]]:
        """
        读取一帧图像（同步方式）
        
        Returns:
            Tuple[bool, Optional[np.ndarray]]: (是否成功, 图像帧)
        """
        if not self.is_opened or not self.cap:
            return False, None
        
        try:
            ret, frame = self.cap.read()
            
            if ret:
                self.stats['total_frames'] += 1
                self.stats['last_frame_time'] = time.time()
                return True, frame
            else:
                logger.warning("读取摄像头帧失败")
                return False, None
                
        except Exception as e:
            logger.error(f"读取摄像头帧异常: {e}")
            return False, None
    
    def start_capture_thread(self):
        """开始异步捕获线程"""
        if self._capture_running:
            logger.warning("捕获线程已在运行")
            return
        
        if not self.is_opened:
            logger.error("摄像头未打开，无法启动捕获线程")
            return
        
        self._capture_running = True
        self._capture_thread = threading.Thread(target=self._capture_loop)
        self._capture_thread.daemon = True
        self._capture_thread.start()
        
        logger.info("摄像头异步捕获线程已启动")
    
    def stop_capture_thread(self):
        """停止异步捕获线程"""
        if not self._capture_running:
            return
        
        self._capture_running = False
        
        if self._capture_thread and self._capture_thread.is_alive():
            self._capture_thread.join(timeout=1.0)
        
        logger.info("摄像头异步捕获线程已停止")
    
    def _capture_loop(self):
        """异步捕获循环"""
        fps_counter = 0
        fps_start_time = time.time()
        
        while self._capture_running and self.is_opened and self.cap:
            ret, frame = self.cap.read()
            
            if ret:
                with self._frame_lock:
                    self._current_frame = frame.copy()
                    self._frame_timestamp = time.time()
                
                # 更新统计
                self.stats['total_frames'] += 1
                fps_counter += 1
                
                # 计算实际FPS
                current_time = time.time()
                if current_time - fps_start_time >= 1.0:  # 每秒更新一次FPS
                    self.stats['fps_actual'] = fps_counter / (current_time - fps_start_time)
                    fps_counter = 0
                    fps_start_time = current_time
                
            else:
                logger.warning("异步捕获帧失败")
                time.sleep(0.01)  # 避免CPU占用过高
            
            # 控制帧率
            if self.fps > 0:
                time.sleep(max(0, 1.0/self.fps - 0.001))
    
    def get_latest_frame(self) -> Tuple[bool, Optional[np.ndarray], float]:
        """
        获取最新帧（异步模式）
        
        Returns:
            Tuple[bool, Optional[np.ndarray], float]: (是否成功, 图像帧, 帧时间戳)
        """
        with self._frame_lock:
            if self._current_frame is not None:
                return True, self._current_frame.copy(), self._frame_timestamp
            else:
                return False, None, 0.0
    
    def get_camera_info(self) -> dict:
        """获取摄像头信息"""
        return {
            'device_id': self.device_id,
            'width': self.width,
            'height': self.height,
            'fps': self.fps,
            'is_opened': self.is_opened,
            'thread_running': self._capture_running
        }
    
    def get_stats(self) -> dict:
        """获取统计信息"""
        return self.stats.copy()
    
    def release(self):
        """释放摄像头资源"""
        logger.info("正在释放摄像头资源...")
        
        # 停止捕获线程
        self.stop_capture_thread()
        
        # 释放摄像头
        if self.cap:
            self.cap.release()
            self.cap = None
        
        self.is_opened = False
        logger.info("摄像头资源已释放")
    
    def __del__(self):
        """析构函数，确保资源被释放"""
        self.release()